package com.ruoyi.demo.util;

import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.demo.controller.JupyterController;
import com.ruoyi.demo.domain.MeetAgenda;
import com.ruoyi.demo.mapper.MeetAgendaMapper;
import com.ruoyi.demo.service.VideoProcessingService;
import com.ruoyi.system.domain.Meet;
import com.ruoyi.system.domain.MeetMaterials;
import com.ruoyi.system.mapper.MeetMapper;
import com.ruoyi.system.mapper.MeetMaterialsMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.env.Environment;

import java.io.File;
import java.io.FileInputStream;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import com.fasterxml.jackson.databind.JsonNode;

@Component
public class MeetingRecordTask {
    private static final Logger log = LoggerFactory.getLogger(MeetingRecordTask.class);
    @Autowired
    private MediaSyncUtil mediaSyncUtil;
    @Autowired
    private JupyterController jupyterController;
    @Value("${ruoyi.profile}")
    private String uploadPath;

    @Autowired
    private MeetAgendaMapper meetAgendaMapper;

    @Autowired
    private MeetMapper meetMapper;

    @Autowired
    private MeetMaterialsMapper meetMaterialsMapper;

    @Autowired
    private MinIOUtil minioUtil;

    @Autowired
    private Environment environment;

    @Autowired
    private VideoProcessingService videoProcessingService;

    /**
     * 定时检查并开始录制（每2分钟执行一次）
     */
    @Scheduled(fixedDelay = 10000)
    public void checkAndStartRecording() {
        try {
            log.info("开始检查会议录制任务...");
            // 获取当前时间附近的议程
            List<MeetAgenda> agendas = meetAgendaMapper.selectCurrentTimeAgendas();

            for (MeetAgenda agenda : agendas) {
                if ("会议签到".equals(agenda.getAgendaTitle())) {
                    // 获取会议信息
                    Meet meet = meetMapper.selectMeetByMeetId(agenda.getMeetId().intValue());
                    if (meet != null && "1".equals(meet.getStatus())) { // 只处理进行中的会议
                        log.info("发现需要录制的会议：{}", meet.getMeetId());
                        // 调用设备接口开始录制
                        startRecording(meet, agenda);
                    }
                }
            }
        } catch (Exception e) {
            log.error("定时检查会议录制任务异常", e);
        }
    }

    /**
     * 开始录制
     */
    private void startRecording(Meet meet, MeetAgenda agenda) {
        try {
            // 1. 首先获取设备列表
            AjaxResult devicesResult = jupyterController.getDevices();
            if (devicesResult.get("code").equals(500)) {
                log.error("获取设备列表失败：{}", devicesResult.get("msg"));
                return;
            }

            // 2. 解析设备信息，使用默认设备
            int videoDeviceId = 0;  // 默认使用第一个视频设备
            int audioDeviceId = 1;   // 默认使用第二个设备作为音频设备

            // 3. 开始录制，使用固定时长进行测试
            int duration = calculateDuration(meet.getStartTime(), meet.getEndTime(), agenda);
            log.info("开始录制会议 {}，时长：{}秒", meet.getMeetId(), duration);

            AjaxResult recordResult = jupyterController.record(videoDeviceId, audioDeviceId, duration, meet.getMeetId().longValue());

            if (recordResult.get("code").equals(500)) {
                log.error("录制失败：{}", recordResult.get("msg"));
                return;
            }

            // 4. 获取录制文件路径
            JsonNode recordData = (JsonNode) recordResult.get("data");
            if (recordData != null) {
                log.info("开始录制，等待{}秒后处理文件", 30);

                // 创建一个新线程等待录制完成，并使用CountDownLatch确保处理完成
                CountDownLatch latch = new CountDownLatch(1);
                Thread processingThread = new Thread(() -> {
                    try {
                        // 等待录制完成（加10秒缓冲时间）
                        Thread.sleep((30 + 10) * 1000);

                        // 获取录制文件名
                        String videoFileName = recordData.get("video_path").asText();
                        String audioFileName = recordData.get("audio_path").asText();

                        log.info("录制完成，开始处理文件 - 视频：{}，音频：{}", videoFileName, audioFileName);

                        // 下载视频文件到本地
                        String localVideoPath = downloadFile(videoFileName, "video");
                        log.info("视频文件下载完成：{}", localVideoPath);

                        // 下载音频文件到本地
                        String localAudioPath = downloadFile(audioFileName, "audio");
                        log.info("音频文件下载完成：{}", localAudioPath);

                        // 5. 处理录制文件
                        SyncResult syncResult = handleRecordedFiles(Long.valueOf(meet.getMeetId()), localVideoPath, localAudioPath);
                        log.info("会议 {} 录制处理完成", meet.getMeetId());

                        // 获取返回的同步后的文件路径和音频文件路径
                        MeetMaterials meetMaterials = syncResult.getMaterials();
                        String syncedFilePath = syncResult.getSyncedFilePath();
                        String audioFilePath = syncResult.getAudioFilePath();
                        log.info("同步后的文件路径：{}", syncedFilePath);
                        log.info("音频文件路径：{}", audioFilePath);

                        //6.同步后文件切片，调用接口
                        videoProcessingService.splitVideoByAgenda(meetMaterials, syncedFilePath, audioFilePath);

                    } catch (Exception e) {
                        log.error("处理录制文件失败", e);
                    } finally {
                        latch.countDown();
                    }
                });
                processingThread.setName("RecordProcessing-" + meet.getMeetId());
                processingThread.start();

                // 等待处理完成，设置超时时间为录制时长的2倍
                if (!latch.await(duration * 2L, TimeUnit.SECONDS)) {
                    log.error("处理录制文件超时");
                }
            }

        } catch (Exception e) {
            log.error("启动录制失败", e);
        }
    }

    /**
     * 计算录制时长（秒）
     */
    private int calculateDuration(Date startTime, Date endTime, MeetAgenda signinAgenda) {
        if (signinAgenda == null || signinAgenda.getStartTime() == null || signinAgenda.getEndTime() == null) {
            // 如果签到时间为空，则不减去签到时间
            long durationMillis = endTime.getTime() - startTime.getTime();
            return (int) (durationMillis / 1000);
        } else {
            // 减去签到时间
            long signinStartMillis = signinAgenda.getStartTime().getTime();
            long signinEndMillis = signinAgenda.getEndTime().getTime();
            long signinDurationMillis = signinEndMillis - signinStartMillis;

            long totalDurationMillis = endTime.getTime() - startTime.getTime();
            long adjustedDurationMillis = totalDurationMillis - signinDurationMillis;
            return (int) (adjustedDurationMillis / 1000);
        }
    }

    /**
     * 下载文件到本地
     */
    private String downloadFile(String remotePath, String type) throws Exception {
        String localFilePath = "E:\\Sync\\" + type + "\\" + new File(remotePath).getName();
        File localFile = new File(localFilePath);
        if (!localFile.getParentFile().exists()) {
            localFile.getParentFile().mkdirs();
        }
        minioUtil.downloadFile(remotePath, localFilePath);
        if (!new File(localFilePath).exists()) {
            throw new RuntimeException("文件下载失败: " + localFilePath);
        }
        return localFilePath;
    }

    /**
     * 处理录制文件
     */
    public SyncResult handleRecordedFiles(Long meetId, String videoPath, String audioPath) {
        try {
            // 检查文件是否存在
            File videoFile = new File(videoPath);
            File audioFile = new File(audioPath);

            if (!videoFile.exists() || !audioFile.exists()) {
                log.error("录制文件不存在 - 视频：{}（{}），音频：{}（{}）",
                        videoPath, videoFile.exists(),
                        audioPath, audioFile.exists());
                throw new RuntimeException("录制文件不存在");
            }

            log.info("开始处理录制文件 - 视频：{}，音频：{}", videoPath, audioPath);

            // 创建保存目录
            String dateDir = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"));
            String meetDir = "meet_" + meetId;
            String baseDir = uploadPath + File.separator + "meetrecords" + File.separator + dateDir + File.separator + meetDir;
            log.info(baseDir);
            File dir = new File(baseDir);
            if (!dir.exists()) {
                dir.mkdirs();
            }

            // 生成同步后的文件名
            String syncedFileName = "synced_" + meetId + "_" + System.currentTimeMillis() + ".mp4";
            String syncedFilePath = baseDir + File.separator + syncedFileName;

            // 执行音视频同步
            String localFilePath = mediaSyncUtil.syncMediaFiles(videoPath, audioPath, syncedFilePath);
            log.info("音视频同步完成：{}", localFilePath);

            // 上传到MinIO
            String minioUrl = minioUtil.uploadVideo(
                    new MockMultipartFile(syncedFileName, syncedFileName, "video/avi", new FileInputStream(localFilePath)),
                    "meet/" + meetId + "/video/",
                    syncedFileName
            );

            log.info("文件上传到MinIO完成：{}", minioUrl);

            // 保存到会议资料表
            MeetMaterials materials = new MeetMaterials();
            materials.setMeetId(meetId);
            materials.setVideoPath(minioUrl);
            materials.setCreatedAt(new Date());
            materials.setIsDeleted("0");
            meetMaterialsMapper.insertMeetMaterials(materials);
            log.info("会议资料保存完成：{}", materials);

            // 删除本地文件

            return new SyncResult(materials, localFilePath, audioPath);
        } catch (Exception e) {
            log.error("处理录制文件失败", e);
            throw new RuntimeException("处理录制文件失败：" + e.getMessage());
        }
    }
}